Шахматы – это
игра на квадратной доске из восьми строк и восьми столбцов. Столбцы нумеруются
буквами от ‘a’ до ‘h’ слева направо,
а строки нумеруются цифрами от ‘1’ до ‘8’ снизу вверх.
Для игры в шахматы Вам следует понять правила, по которым ходят и атакуют
фигуры. Одной из шахматных фигур является пешка. Пешка бьет по диагонали, на
один квадрат вверх и влево или вправо. Например, если пешка находится на c3, то она угрожает полям d4 и b4.
Другой шахматной фигурой является король. Король может двигаться или атаковать
на один квадрат в любом направлении по вертикали, горизонтали или диагонали.
Когда пешка (или король) атакует клетку, то она передвигается на нее и бьет
фигуру, которая там находится.
Вам заданы
начальные координаты короля, пешки A и пешки B. Найдите наименьшее количество
ходов, за которое король сможет побить пешку A. Король не может ходить на поля,
которые находятся под ударом пешек, а также не может выходить за пределы доски.
Король может побить пешку B, однако делать это не обязательно. Пешкам передвигаться
запрещено.
Вход. Состоит из нескольких тестов. Каждая строка описывает
один тест и содержит начальное положение короля, пешки A и пешки B. Каждая
позиция описывается двумя символами. Первый символ задает столбец (‘a’ – ‘h’), а второй
символ задает строку (‘1’ – ‘8’). Все три
позиции разные. Начальное положение короля не находится под ударом ни одной
пешки.
Выход. Для каждого теста вывести в отдельной строке наименьшее
количество ходов, за которое король сможет побить пешку A.
Пример
входа |
Пример
выхода |
c4 e6 d5 g2 a8 a2 a3 b1 c1 |
2 6 7 |
РЕШЕНИЕ
графы - поиск в ширину
Анализ алгоритма
Рассмотрим два
варианта движения короля:
1. Король
направляется к пешке А несмотря на положение пешки В и съедает ее;
2. Король
направляется к пешке В, съедает ее и потом двигается к пешке А.
В обоих случаях
при движении короля используется кратчайший путь, который находится поиском в
ширину. Находим наименьшее количество ходов в первом и во втором случаях и
возвращаем наименьшее среди них значение. Второй случай необходим, например, если изначально пешка А
находится под ударом пешки B.
В поля,
находящиеся под ударом пешек, изначально поставим значения 1000. Таким образом
при поиске в ширину король на них не зайдет. Начальные положения короля и двух
пешек занесем соответственно в переменные (kx,
ky), (pax, pay), (pbx, pby).
Запустим bfs(kx, ky). Занесем в переменные a
и b наименьшее число ходов, которыми
можно добраться до пешки А и В соответственно: a = m[pax][pay], b = m[pbx][pby]. Если пешка В сбивается, то следует
запустить bfs(pbx, pby), найдя таким образом кратчайший
путь от пешки В до А. Добавим к b
значение m[pax][pay] после второго вызова bfs. Таким образом в a содержится длина кратчайшего пути короля до достижения цели без
сбивания пешки В, а в b – со
сбиванием. Вычисляем меньшее значение среди a
и b.
Реализация алгоритма
Шахматную доску храним
в массиве m. Очередь пар d используется для поиска в ширину и содержит
координаты полей шахматной доски (x, y).
Массивы xx и yy описывают возможные ходы короля: из клетки (i, j)
король может пойти в любую из клеток (i
+ xx[k], j + yy[k]), где 1 ≤
k ≤ 8.
int m[10][10];
deque<pair<int,int> > d;
int xx[8] = {1, 1, 1, -1, -1, -1, 0, 0};
int yy[8] = {-1, 0, 1, -1, 0, 1, 1, -1};
Функция cango
проверяет, не находится ли поле (x, y) за границами шахматной доски.
int cango(int
x, int y)
{
if ((x <
1) || (x > 8) || (y < 1) || (y > 8) || (m[x][y] >= 0))
return
0;
return 1;
}
Функция bfs реализует поиск в ширину из клетки (x, y). С ее помощью ищем
кратчайший путь короля до каждой из пешек.
void bfs(int
x, int y)
{
m[x][y] = 0;
d.push_back(make_pair(x,y));
while(!d.empty())
{
pair<int,int> temp = d[0]; d.pop_front();
Перебираем все возможные ходы короля.
for(int i = 0; i < 8; i++)
{
int dx = temp.first + xx[i];
int dy = temp.second + yy[i];
if (cango(dx, dy))
{
m[dx][dy] = m[temp.first][temp.second]
+ 1;
d.push_back(make_pair(dx, dy));
}
}
}
}
Функция attackPawns возвращает наименьшее
количество ходов, за которое король сможет побить пешку A.
int attackPawns(void)
{
memset(m,-1,sizeof(m));
В поля, находящиеся под ударом пешек, поставим значения 1000.
Это делается для того, чтобы при поиске в ширину король в них не зашел.
m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;
m[pbx-1][pby+1] = m[pbx+1][pby+1] = 1000;
bfs(kx,ky);
До пешки А король может добраться
минимум за а ходов, а до пешки B за b ходов.
int a =
m[pax][pay], b = m[pbx][pby];
memset(m,-1,sizeof(m));
m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;
Вычисляем кратчайший путь от пешки В
до пешки А.
bfs(pbx,pby); b += m[pax][pay];
В переменной a содержится
длина кратчайшего пути короля до пешки A без сбивания пешки В, а в переменной b с ее сбиванием. Возвращаем меньшее
значение среди a и b.
return (a
< b) ? a : b;
}
Основная часть программы. Читаем
входные данные. Находим и выводим ответ.
while(scanf("%c%c
%c%c %c%c\n",&kx, &ky, &pax, &pay, &pbx,
&pby) == 6)
{
kx -= 'a' -
1; ky -= '1' - 1; pax -= 'a' - 1; pay -= '1'
- 1;
pbx -= 'a'
- 1; pby -= '1' - 1;
res = attackPawns();
printf("%d\n",res);
}